package logic

import (
	"bluebell_qimi/dao/mysql"
	"bluebell_qimi/dao/redis"
	"bluebell_qimi/models"
	"bluebell_qimi/pkg/snowflake"
	"go.uber.org/zap"
)

// 创建帖子
func CreatePost(p *models.Post) (err error) {
	//1. 生成post id
	p.PostID = snowflake.GenID()
	//2. 保存到数据库返回
	err = mysql.CreatePost(p)
	if err != nil {
		return err
	}
	err = redis.CreatePost(p.PostID, p.CommunityID)
	return
}

// 根据帖子id查询帖子详情数据
func GetPostById(pid int64) (data *models.ApiPostDetail, err error) {
	//查询并组合接口想要的数据
	post, err := mysql.GetPostById(pid)
	if err != nil {
		zap.L().Error("mysql.GetPostById(pid) failed", zap.Int64("pid", pid), zap.Error(err))
		return
	}

	//根据作者id查询作者信息
	user, err := mysql.GetUserById(post.AuthorID)
	if err != nil {
		zap.L().Error("mysql.GetUserById(post.AuthorID)", zap.Int64("author_id", post.AuthorID), zap.Error(err))
		return
	}

	//根据社区id查询社区详情
	community, err := mysql.GetCommunityDetailByID(post.CommunityID)
	if err != nil {
		zap.L().Error("mysql.GetCommunityDetailByID(post.CommunityID)", zap.Int64("community_id", post.CommunityID), zap.Error(err))
		return
	}

	//根据投票的key查询当前id的投票信息
	count, err := redis.GetPostVoteDataByID(pid)

	data = &models.ApiPostDetail{
		AuthorName:      user.Username,
		VoteNum:         count,
		Post:            post,
		CommunityDetail: community,
	}
	return
}

// 获取帖子列表和详细信息
func GetPostList(page, size int64) (data []*models.ApiPostDetail, err error) {
	posts, err := mysql.GetPostList(page, size)
	if err != nil {
		return nil, err
	}
	//存储帖子的详细信息
	data = make([]*models.ApiPostDetail, 0, len(posts))
	for _, post := range posts {
		//根据作者id查询作者信息
		user, err := mysql.GetUserById(post.AuthorID)
		if err != nil {
			zap.L().Error("mysql.GetUserById(post.AuthorID)", zap.Int64("author_id", post.AuthorID), zap.Error(err))
			continue
		}

		//根据社区id查询社区详情
		community, err := mysql.GetCommunityDetailByID(post.CommunityID)
		if err != nil {
			zap.L().Error("mysql.GetCommunityDetailByID(post.CommunityID)", zap.Int64("community_id", post.CommunityID), zap.Error(err))
			continue
		}

		postDetail := &models.ApiPostDetail{
			AuthorName:      user.Username,
			Post:            post,
			CommunityDetail: community,
		}
		data = append(data, postDetail)
	}
	return
}

// 升级版获取帖子列表，按热度或者时间排序
func GetPostList2(p *models.ParamPostList) (data []*models.ApiPostDetail, err error) {
	// 2. 去redis查询postid的所有帖子列表，根据时间查帖子和根据热度查帖子，帖子的postid以ids返回
	//记住这个相对位置概念，下面redis.GetPostVoteData(ids)和mysql.GetPostListByIDs(ids)都是以此相对位置开始查找，所以同样的下标对应相同的帖子和点赞数
	//value以ids形式存储，其中value是帖子的id，切片保存的是value的相对位置
	ids, err := redis.GetPostIDsInOrder(p)
	if err != nil {
		return
	}
	if len(ids) == 0 {
		zap.L().Warn("redis.GetPostIDsInOrder(p) return 0 data")
		return
	}

	// 3. 根据postid去数据库查询帖子详细信息
	//提前查询好每篇帖子的投票数，没投过票的帖子的voteData为空，切片形式保存相对帖子位置下对应的票数
	voteData, err := redis.GetPostVoteData(ids)
	if err != nil {
		return
	}

	//根据post_id  返回的数据还要按照给定的ids的相对顺序返回
	posts, err := mysql.GetPostListByIDs(ids)

	if err != nil {
		return
	}
	//将帖子的作者及分区信息查询出来填充到帖子中
	//todo:和GetCommunityPostList中的for循环一样，可以把下面写成一个函数
	data, err = forGetPost(posts, voteData)
	return
}

// 获取社区帖子列表
func GetCommunityPostList(p *models.ParamPostList) (data []*models.ApiPostDetail, err error) {
	// 2. 去redis查询postid的所有帖子列表，根据时间查帖子和根据热度查帖子，帖子的postid以ids返回
	ids, err := redis.GetCommunityPostIDsInOrder(p)
	if err != nil {
		return
	}
	if len(ids) == 0 {
		zap.L().Warn("redis.GetCommunityPostIDsInOrder(p) return 0 data")
		return
	}

	// 3. 根据postid去数据库查询帖子详细信息
	//提前查询好每篇帖子的投票数，没投过票的帖子的voteData为空
	voteData, err := redis.GetPostVoteData(ids)
	if err != nil {
		return
	}

	//根据post_id  返回的数据还要按照给定的ids顺序返回
	posts, err := mysql.GetPostListByIDs(ids)

	if err != nil {
		return
	}
	//将帖子的作者及分区信息查询出来填充到帖子中
	data, err = forGetPost(posts, voteData)
	return
}

// 将两个查询帖子逻辑合二为一的函数(1.按照分数或者时间  2. 按照社区）
func GetPostListNew(p *models.ParamPostList) (data []*models.ApiPostDetail, err error) {
	if p.CommunityID == 0 {
		//查所有
		//127.0.0.1:8084/api/v1/posts2
		//127.0.0.1:8084/api/v1/posts2?page=1&size=2&order=time
		//127.0.0.1:8084/api/v1/posts3
		//127.0.0.1:8084/api/v1/posts3?page=1&size=2&order=time
		data, err = GetPostList2(p)
	} else {
		//根据社区id查询
		//127.0.0.1:8084/api/v1/posts3?community_id=1
		//127.0.0.1:8084/api/v1/posts3?page=1&size=10&community_id=1
		//127.0.0.1:8084/api/v1/posts3?page=1&size=10&order=time&community_id=2
		data, err = GetCommunityPostList(p)
	}
	if err != nil {
		zap.L().Error("GetPostListNew  failed", zap.Error(err))
		return nil, err
	}
	return
}

// 循环遍历帖子填充data信息
func forGetPost(posts []*models.Post, voteData []int64) (data []*models.ApiPostDetail, err error) {
	for idx, post := range posts {
		//根据作者id查询作者信息
		user, err := mysql.GetUserById(post.AuthorID)
		if err != nil {
			zap.L().Error("mysql.GetUserById(post.AuthorID)", zap.Int64("author_id", post.AuthorID), zap.Error(err))
			continue
		}

		//根据社区id查询社区详情
		community, err := mysql.GetCommunityDetailByID(post.CommunityID)
		if err != nil {
			zap.L().Error("mysql.GetCommunityDetailByID(post.CommunityID)", zap.Int64("community_id", post.CommunityID), zap.Error(err))
			continue
		}

		postDetail := &models.ApiPostDetail{
			AuthorName:      user.Username,
			VoteNum:         voteData[idx], //voteData和posts查找出来的相对相对顺序是一样的，所以用相对顺序即可查到voteData下的投票数
			Post:            post,
			CommunityDetail: community,
		}
		data = append(data, postDetail)
	}
	return
}
